/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package ua.yandex.prodcons.utilconcurrent;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * @author Neophron
 */
public class RingBuffer {

    private final int nN;
    private int oldest, newest, count;
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    private final List<Integer> elements;

    public RingBuffer(int nN) {
        this.nN = nN;
        count = 0;
        oldest = 0;
        newest = nN - 1;
        elements = new ArrayList<>(nN);
        for (int i = 0; i < nN; i++) {
            elements.add(null);
        }
    }

    private int next(int n) {
        int r = n;
        r++;
        if (r == nN) {
            return 0;
        } else {
            return r;
        }
    }

    public void put(int el) throws InterruptedException {
        lock.lock();
        try {
            while (count == nN) {
                notFull.await();
            }
            newest = next(newest);
            elements.set(newest, el);
            count++;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }

    public int take() throws InterruptedException {
        lock.lock();
        try {
            while (count == 0) {
                notEmpty.await();
            }
            int res = elements.get(oldest);
            elements.set(oldest, null);
            oldest = next(oldest);
            count--;
            notFull.signal();
            return res;
        } finally {
            lock.unlock();
        }
    }

}
